﻿using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System.Text;
using System.Text.Json;

namespace AiQiuQuan.Sport.Core
{
    // <summary>
    /// TraceDelegatingHandler
    /// </summary>
    public class TraceDelegatingHandler : DelegatingHandler
    {
        private readonly ILogger<TraceDelegatingHandler> _logger;
        private readonly IHttpContextAccessor _httpContextAccessor;

        /// <summary>
        /// ctor
        /// </summary>
        public TraceDelegatingHandler(
            ILogger<TraceDelegatingHandler> logger,
            IHttpContextAccessor httpContextAccessor)
        {
            _logger = logger;
            _httpContextAccessor = httpContextAccessor;
        }

        /// <summary>
        /// SendAsync
        /// </summary>
        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            //traceid
            if (!request.Headers.Contains(CommonData.TraceKey))
            {
                var traceId = string.Empty;
                if (_httpContextAccessor.HttpContext != null && _httpContextAccessor.HttpContext.Request?.Headers != null)
                {
                    traceId = _httpContextAccessor.HttpContext.Request?.Headers[CommonData.TraceKey];
                }

                traceId = string.IsNullOrWhiteSpace(traceId) ? Guid.NewGuid().ToString("N") : traceId;
                request.Headers.Add(CommonData.TraceKey, traceId);
            }

            var response = await base.SendAsync(request, cancellationToken);
            //记录请求日志
            await TraceRequestInfoAsync(request, response);

            return response;
        }

        /// <summary>
        /// Send
        /// </summary>
        protected override HttpResponseMessage Send(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            return SendAsync(request, cancellationToken).Result;
        }

        #region private methods

        private async Task TraceRequestInfoAsync(HttpRequestMessage request, HttpResponseMessage response)
        {
            if (request.Content != null && request.Content.IsMimeMultipartContent())
            {
                return;
            }

            try
            {
                var dic = new Dictionary<string, object>
                {
                    { "url", request.RequestUri.ToString() },
                    { "HttpClientTraceInfo", 1 }
                };
                foreach (var item in request.Headers)
                {
                    dic.TryAdd(item.Key, item.Value);
                }

                if (request.Content != null)
                {
                    if (!request.Content.IsMimeMultipartContent())
                    {
                        var data = await request.Content.ReadAsStringAsync();
                        dic.Add("request_data", data);
                    }
                    else
                    {
                        var stringBuilder = new StringBuilder();
                        foreach (var item in request.Content as MultipartContent)
                        {
                            stringBuilder.AppendLine($"{item.Headers.ContentType}_{item.Headers.ContentDisposition}");
                        }

                        dic.Add("request_data", stringBuilder.ToString());
                    }
                }

                if (response.Content != null)
                {
                    var contentType = response.Content.Headers?.ContentType?.ToString() ?? string.Empty;
                    if (contentType.Contains("application/json") || contentType.Contains("application/xml") || contentType.Contains("text/"))
                    {
                        var responseTxt = await response.Content.ReadAsStringAsync();
                        dic.Add("response_data", responseTxt);
                    }
                }

                var logstr = JsonSerializer.Serialize(dic, new JsonSerializerOptions { Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping }).Replace(@"\", "");
                _logger.LogInformation(logstr);
            }
            catch { }
        }

        #endregion private methods
    }
}
